﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MethodWorx.CMS.Requests;
using MethodWorx.Core.DomainModel;
using MethodWorx.Core.Validation;
using MethodWorx.CMS.Workflow;
using MethodWorx.CMS.Content;

namespace MethodWorx.CMS.Services
{
    public class WorkflowService
    {
        private IUnitOfWorkFactory uowFactory;

        public WorkflowService(IUnitOfWorkFactory uowFactory)
        {
            this.uowFactory = uowFactory;
        }

        public WorkflowConfiguration CreateWorkflow(WorkflowRequest request, IValidationProvider validation)
        {
            WorkflowConfiguration config = null;

            using (var uow = this.uowFactory.Begin())
            {
                try
                {
                    config = request.Page.AddWorkflow(
                        request.Name,
                        request.InvokeOnHttpMethod,
                        request.InvokeOnPageEvent);

                    uow.RegisterChanged(request.Page);
                    uow.Commit();
                }
                catch (BusinessRuleException bre)
                {
                    //  handle the errors up the stack
                    if (!bre.AddToValidationProvider(validation))
                        throw;
                }
            }

            return config;
        }

        public WorkflowConfiguration SaveWorkflow(WorkflowRequest workflowRequest, IValidationProvider validation)
        {
            WorkflowConfiguration config = null;

            using (var uow = this.uowFactory.Begin())
            {
                try
                {
                    config =
                        workflowRequest.Page.GetWorkflowConfiguration(true).FirstOrDefault(
                            w => w.Name.ToLower() == workflowRequest.OriginalName.ToLower());
                    if(config == null)
                        throw new BusinessRuleException("Workflow Not Found");

                    config.Name = workflowRequest.Name;
                    config.Shared = workflowRequest.Shared;
                    config.InvokeOnPageEvent = workflowRequest.InvokeOnPageEvent;
                    config.InvokeOnHttpMethod = workflowRequest.InvokeOnHttpMethod;

                    uow.RegisterChanged(workflowRequest.Page);

                    if(workflowRequest.Shared)
                    {
                        //
                        //  ok, is the workflow part of the page or its template
                        if(!workflowRequest.Page.Template.ContainsWorkflow(config))
                        {
                            workflowRequest.Page.RemoveWorkflow(config);
                            workflowRequest.Page.Template.AddWorkflow(config);
                        }
                        uow.RegisterChanged(workflowRequest.Page.Template);
                    }

                    uow.Commit();
                }
                catch (BusinessRuleException bre)
                {
                    //  handle the errors up the stack
                    if (!bre.AddToValidationProvider(validation))
                        throw;
                }
            }

            return config;
        }

        public void SaveWorkflow(Page instance, string workflowName, Guid? stepId, Guid? parentStepId, WorkflowConfigurationStep model)
        {
            using (var unitOfWork = this.uowFactory.Begin())
            {
                var workflow = instance.GetWorkflowConfiguration(true).FirstOrDefault(w => w.Name.ToLower() == workflowName.ToLower());
                if (workflow == null)
                    throw new BusinessRuleException("Workflow not found");

                if (stepId == null && parentStepId == null)
                {
                    workflow.StartingStep = model;
                }
                else if(stepId == null && parentStepId != null)
                {
                    var found = workflow.FindStep(parentStepId.Value);
                    //  put the children back in
                    if (model.Steps == null && found.Steps != null)
                        model.Steps = found.Steps;
                    found.Steps = new WorkflowConfigurationStep [] { model };
                }

                unitOfWork.RegisterChanged(instance);
                unitOfWork.RegisterChanged(instance.Template);
                //  and commit
                unitOfWork.Commit();
            }
        }



        public void DeleteStep(Page instance, string workflowName, Guid stepId)
        {
            using (var unitOfWork = this.uowFactory.Begin())
            {
                var workflow = instance.GetWorkflowConfiguration(true).FirstOrDefault(w => w.Name.ToLower() == workflowName.ToLower());
                if (workflow == null)
                    throw new BusinessRuleException("Workflow not found");

                workflow.DeleteStep(stepId);

                unitOfWork.RegisterChanged(instance);
                unitOfWork.RegisterChanged(instance.Template);
                //  and commit
                unitOfWork.Commit();
            }

            
        }
    }
}
